home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_069 / spew / spew.c < prev   
C/C++ Source or Header  |  1992-05-06  |  14KB  |  653 lines

  1. /*
  2.  * SPEW.C
  3.  */
  4. #ifndef lint
  5. static char *cpr[]={
  6. "  Copyright 1987 Greg Smith",
  7. "  Permission is granted to freely use and distribute this software",
  8. "provided this notice is left attached and no monetary gain is made."
  9. };
  10. #endif
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #ifdef unix
  14. #include <strings.h>
  15. #else
  16. extern char *strcpy ();
  17. #define index strchr
  18. #define rindex strrchr
  19. extern char *index ();
  20. extern char *rindex ();
  21. #endif
  22. extern char *malloc();
  23. char *my_alloc();
  24. extern int atoi();
  25. char *save();
  26. #define TRUE 1
  27. #define FALSE 0
  28. #define MAGIC 4        /* distinguish compressed file from normal */
  29.  
  30. /*--------------- system configuration ------------------*/
  31.  
  32. /* define some parameters */
  33.  
  34. #define MAXCLASS 300        /* max # of classes */
  35. #define MAXLINE 256        /* max size of input line */
  36. #define MAXDEF 1000        /* max # bytes in a definition */
  37.  
  38. /* Define the default rulesfile */
  39.  
  40. #ifndef DEFFILE
  41. # define DEFFILE "headline"
  42. #endif
  43.  
  44. /* Define the environment variable which is to be interrogated for
  45.    name of rules file before DEFFILE is used. Delete this to
  46.    remove the code that calls getenv() */
  47.  
  48. #define ENVIRON "RULESFILE"
  49.  
  50. /* Define the random number generator */
  51.  
  52. extern long getpid();
  53. extern int rand(), srand();
  54.     /* SETRAND must be complete statement: note semicolon */
  55. #define SETRAND (void)srand((int) time((long *)0) );
  56.     /* ROLL(n) returns integer 0..n-1 */
  57. #define ROLL(n) ((((long)rand()&0x7ffffff)>>5)%(n))
  58.  
  59. /* Enable '-d' dump debug option by defining DUMP */
  60. #define DUMP
  61.  
  62. /*---------------------------------------------------*/
  63.  
  64. FILE *InFile;
  65.  
  66. typedef struct def_struct{
  67.     int cumul;            /* cumulative weights */
  68.     char *string;            /* string which defines it */
  69.     struct def_struct *next;    /* link to next */
  70. } defn;
  71. defn *process();
  72. /*
  73.  * within a definition, names of subdefinitions are bracketed in BSLASH
  74.  * and SLASH chars. The whole definition ends with a '\0'.
  75.  * The SLASH character is always follwed by a variant tag - default is ' '.
  76.  */
  77. #define BSLASH '\\'
  78. #define SLASH  '/'
  79. #define VBAR     '|'
  80.  
  81. typedef struct{
  82.     int weight;    /* total weight of definitions in class */
  83.     defn *list;    /* list of them */
  84.     char *name;    /* name of this class */
  85.     char *tags;    /* pointer to list of tags */
  86. } class;
  87.  
  88. class * Class;    /* pointer to array of class records */
  89. char *NullTags = " ";    /* default tags ( shared ) */
  90. int Classes;    /* number of them */
  91. int HowMany = 1;
  92. int CompIn = FALSE;    /* is input file in compressed format? */
  93. int CompMain;        /* class # of MAIN class when compressed */
  94.  
  95. char InLine[MAXLINE];
  96.  
  97. main(argc, argv )
  98. int argc;
  99. char **argv;
  100. {
  101.     char *fname;
  102.     char main_class[20];
  103.     int i, c_flag = FALSE;
  104. #ifdef DUMP
  105.     int d_flag = FALSE;
  106. #endif DUMP
  107. #ifdef ENVIRON
  108.     extern char *getenv();
  109.     fname = getenv( ENVIRON );
  110. #else
  111.     fname = NULL;
  112. #endif ENVIRON
  113.  
  114.     while( argc > 1 ){
  115.         if( isdigit(*argv[1]) ){
  116.             HowMany = atoi(*++argv);
  117.             --argc;
  118.         }else if( strcmp( argv[1], "-c") == 0 ){
  119.             c_flag = TRUE;     /* 'compress' option */
  120.             --argc;
  121.             ++argv;
  122. #ifdef DUMP
  123.         }else if( strcmp( argv[1], "-d" )== 0 ){
  124.             d_flag = TRUE;    /* 'dump' option */
  125.             --argc;
  126.             ++argv;
  127. #endif DUMP
  128.         }else break;
  129.     }
  130.     if( argc > 1 ) fname = argv[1];
  131.     if (fname == NULL ) fname = DEFFILE;
  132.     InFile = fopen( fname, "r" );
  133.     if( InFile == NULL ){
  134.         fprintf( stderr, "Can\'t open: %s\n", fname );
  135.         exit(1);
  136.     }
  137.     init();
  138. #ifdef DUMP
  139.     if( d_flag ){
  140.         dump();
  141.         exit(0);
  142.     }
  143. #endif DUMP
  144.     if( c_flag ){
  145.         compress();
  146.     }else{
  147.         if( CompIn ) sprintf( main_class, "%d/ ", CompMain);
  148.         else         strcpy( main_class, "MAIN/ ");
  149.         for(i=0; i<HowMany; ++i) display(main_class,' ');
  150.     }
  151.     exit(0);
  152. }
  153.  
  154. init(){
  155.     int c;
  156.  
  157.     SETRAND        /* spin random number gen */
  158.     c = getc( InFile );    /* is compressed? */
  159.     CompIn = ( c== MAGIC );    /* set flag */
  160.     if( CompIn ){
  161.         readcomp();    /* read compressed version */
  162.     }else{
  163.         ungetc(c, InFile );
  164.         readtext();
  165.     }
  166. }
  167. readtext(){
  168.     register class *cp;
  169.     register defn *dp;
  170.     defn **update;
  171.     int clcomp();
  172.  
  173.     Class = (class *)my_alloc( (unsigned)(MAXCLASS * sizeof(class)) );
  174.     Classes = 0;
  175.  
  176.     cp = Class;
  177.     readline();
  178.     if( InLine[0]!='%'){
  179.         fprintf( stderr,"Class definition expected at: %s\n", InLine);
  180.         exit(1);
  181.     }
  182.     while( InLine[1] != '%' ){
  183.         if( Classes == MAXCLASS ){
  184.             fprintf(stderr,"Too many classes -- max = %d\n", MAXCLASS);
  185.             exit(1);
  186.         }
  187.         setup( cp );        /* set up the class struct */
  188.         readline();
  189.         if( InLine[0] == '%' ){
  190.             fprintf( stderr, "Expected class instance at: %s\n", InLine);
  191.             exit(1);
  192.         }
  193.         update = &(cp->list);    /* update pointer */
  194.         do{
  195.             dp = process();
  196.             *update = dp;
  197.             cp->weight += dp->cumul;    /* add new stuff */
  198.             dp->cumul = cp->weight;        /* set breakpoint */
  199.             update = &(dp->next);
  200.         }while( readline(), InLine[0]!= '%' );
  201.         ++Classes;        /* count them */
  202.         ++cp;
  203.         *update = NULL;
  204.     }
  205.     qsort( (char*)Class, Classes, sizeof( class ), clcomp);
  206. }
  207. /*
  208.  * display is given a class name ( delimited by SLASH, not '\0' ),
  209.  * and will (1) find its class descriptor, by calling lookup
  210.  * (2) pick a definition  (3) output that definition, and
  211.  * recursively display any definitions in it, and convert any escapes.
  212.  * The variant tag after the SLASH is used to pick out the appropriate
  213.  * variants. If that variant tag is '&', the tag 'deftag' is used, which
  214.  * is the active variant of the containing activation.
  215.  */
  216. display(s,deftag)
  217. char *s;
  218. int deftag;
  219. {
  220.     register class *cp;
  221.     register defn *dp;
  222.     register char *p;
  223.     class *lookup();
  224.     int i,variant,incurly;
  225.     register int c,writing;
  226.  
  227.     if( CompIn ){        /* input is compressed */
  228.         cp = &Class[ atoi(s) ];        /* explicit class # */
  229.     }else{
  230.         cp = lookup(s);
  231.         if( cp == NULL ) {        /* none found */
  232.             printf("???");
  233.             while( *s != SLASH ) putchar( *s++ );
  234.             printf("???");
  235.             return;
  236.         }
  237.     }
  238.     c = index(s,SLASH)[1];        /* get variant tag */
  239.     if( c != '&' ) deftag=c;    /* use given tag */
  240.     p = index(cp->tags, deftag);        /* look it up */
  241.     if(p == NULL ){
  242.         variant = 0;
  243.         printf("??/%c??", deftag );
  244.         deftag = ' ';        /* for passing as deftag */
  245.     }else variant = p - cp->tags;
  246.  
  247.     i = ROLL( cp->weight );
  248.     dp = cp->list;
  249.     while(dp->cumul <= i){    /* pick one based on cumul. weights */
  250.         dp = dp->next;
  251.     }
  252.  
  253.     incurly = 0;        /* not in curlies */
  254.     writing = 1;        /* writing */
  255.     p = dp->string;        /* this is the string */
  256.     for(;;)switch(c = *p++){
  257.         case '\0': return;
  258.         case BSLASH:
  259.             if(( c = *p++) == '\0' ) return; /* ?? */
  260.             else if( c == '!' ){
  261.                  if(writing)putchar('\n'); /* \! = newline */
  262.             }else if( isalnum(c) ){    /* reference */
  263.                 if(writing)display(p-1,deftag);  /* recurse */
  264.                 while( *p!=SLASH )++p;
  265.                 p += 2;        /* skip variant tag */
  266.             }else{
  267.                 if(writing) putchar(c);
  268.             }
  269.             break;
  270.         case '{':
  271.             if( !incurly ){
  272.                 incurly = 1;
  273.                 writing = (variant == 0 );
  274.             }else{
  275.                 if( writing )putchar('{');
  276.             }
  277.             break;
  278.         case VBAR:
  279.             if( incurly ){
  280.                 writing = ( variant == incurly++ );
  281.             }else{
  282.                 putchar(VBAR);
  283.             }
  284.             break;
  285.         case '}':
  286.             if( incurly ){
  287.                 writing = 1;
  288.                 incurly = 0;
  289.             }else putchar('}');
  290.             break;
  291.         default:
  292.             if( writing) putchar(c);
  293.     }
  294. }
  295. class *
  296. lookup( str )        /* delimited by SLASH, not '\0' */
  297. char *str;
  298. {
  299.     int first, last, try, comp;
  300.     int namecomp();
  301.  
  302.     first = 0;
  303.     last = Classes-1;
  304.     while( first <= last ){
  305.         try = (first+last)>>1;
  306.         comp = namecomp( str, Class[try].name );
  307.         if( comp == 0 ) return &Class[try];
  308.         if( comp > 0 ) first = try+1;
  309.         else last = try-1;
  310.     }
  311.     return NULL;
  312. }
  313. int namecomp(a,b)    /* 'a' is delim. by SLASH, 'b' by NULL */
  314. register char *a,*b;
  315. {
  316.     register int ac;
  317.     for(;;){
  318.         ac = *a++;
  319.         if(ac == SLASH ) ac = '\0';
  320.         if( ac < *b ) return -1;
  321.         if( ac > *b++ ) return 1;
  322.         if( ac == '\0' ) return 0;
  323.     }
  324. }
  325. readline(){
  326.     register char *p;
  327.     do{
  328.         if( fgets( InLine, MAXLINE, InFile ) == NULL ){
  329.             InLine[0] = InLine[1] = '%';
  330.             InLine[2] = '\0';    /* create EOF */
  331.         }else if( (p=rindex( InLine, '\n'))!= NULL ) *p = '\0';
  332.         p = InLine;
  333.         while( (p = index( p, BSLASH )) != NULL ){
  334.             if(p[1] == '*' ){
  335.                 *p = 0;    /* kill comment */
  336.                 break;
  337.             }else ++p;
  338.         }
  339.     }while( InLine[0] == '\0' );
  340. }
  341.  
  342. int clcomp(a,b)            
  343. register class *a,*b;
  344. {
  345.     if( a==b) return 0;
  346.     return strcmp( a->name, b->name );
  347. }
  348. char *save(str)
  349. char *str;
  350. {
  351.     register char *p;
  352.     p = my_alloc( (unsigned)((strlen(str)+1)*sizeof(char)));
  353.     return strcpy(p,str);
  354. }
  355. /*
  356.  * setup a class record. The 'class' line is in InLine.
  357.  */
  358. setup(cp)
  359. register class *cp;
  360. {
  361.     char temp[100];
  362.     register char *p,*p2;
  363.  
  364.     p = &InLine[1];        /* point after the % */
  365.     while( *p == ' ' )++p;
  366.     if( !isalnum(*p) ) goto baddec;
  367.     p2 = temp;
  368.     do *p2++ = *p++; while( isalnum(*p));
  369.     *p2 = '\0';
  370.     cp->weight = 0;        /* save the name of it */
  371.     cp->name = save( temp );
  372.     cp->list = NULL;
  373.     cp->tags = NullTags;    /* by default */
  374.     for(;;)switch(*p++){
  375.     case '\0':
  376.         return;    /* all done; */
  377.     case ' ':
  378.         break;        /* allowed those */
  379.     case '{':        /* tags list */
  380.         if( cp->tags  != NullTags ) goto baddec; /* already */
  381.         p2 = temp;
  382.         *p2++ = ' ';    /* provide null tag */
  383.         while(*p!='}'){
  384.             if( !isalnum(*p)) goto baddec;
  385.             *p2++ = *p++;
  386.         }
  387.         ++p;    /* junk rh brace */
  388.         *p2 = 0;
  389.         cp->tags = save(temp);
  390.         break;
  391.     default: goto baddec;
  392.     }
  393.   baddec:
  394.     fprintf(stderr,"Bad class header: %s\n", InLine );
  395.     exit(1);
  396. }
  397. /*
  398.  * create a 'processed' version of the InLine, and return a pointer to
  399.  * the definition. The 'cumul' field is temporarily used to hold the
  400.  * assigned weight of the line.
  401.  */
  402. defn *process(){
  403.     static char stuff[ MAXDEF ];
  404.     register char *p,*pout;
  405.     register defn *dp;
  406.     register int c;
  407.  
  408.     dp = (defn *) my_alloc( (unsigned) sizeof( defn ));
  409.  
  410.     p = InLine;
  411.     pout = stuff;
  412.     if( *p == '(' ){        /* get a weight */
  413.         while(*++p ==' ');    /* scan */
  414.         if(!isdigit(*p)) goto badweight;
  415.         c = *p - '0';
  416.         while(isdigit(*++p)) c = c*10 + (*p - '0' );
  417.         while( *p == ' ')++p;
  418.         if( *p != ')') goto badweight;
  419.         ++p;
  420.         dp->cumul = c;
  421.     }else{
  422.         dp->cumul = 1;    /* default weight */
  423.     }
  424.     while((c = *p++)!='\0')switch(c){
  425.     case BSLASH:
  426.         *pout++ = BSLASH;
  427.         if( isalnum(*p)){    /* is a ref */
  428.             do{ *pout++ = *p++;
  429.             }while( isalnum(*p));
  430.             *pout++ = SLASH;        /* delimit */
  431.             if( *p == SLASH ){    /* get variant char */
  432.                 ++p;
  433.                 if( !isalnum(*p)&& *p!= ' ' && *p!= '&' ){
  434.                     *pout++ = ' ';
  435.                 }else *pout++ = *p++;
  436.             }else *pout++ = ' ';
  437.         }else{
  438.             *pout++ = *p;
  439.             if( *p!= '\0'){
  440.                  ++p;
  441.             }else{
  442.                 --pout;    /* delete spurious '\' */
  443.                 readline();    /* get new line */
  444.                 p = InLine;    /* point to it */
  445.             }
  446.         }
  447.         break;
  448.     default:
  449.         *pout++ = c;
  450.     }
  451.     *pout = '\0';
  452.     dp->string = save( stuff );
  453.     return dp;
  454.  
  455.   badweight:
  456.     fprintf(stderr, "Bad line weight: %s\n", InLine );
  457.     exit(1);
  458.     /*NOTREACHED*/
  459. }
  460. #ifdef DUMP
  461. dump(){
  462.     register class *cp;
  463.     register defn *dp;
  464.     register int i;
  465.     for( i=0, cp=Class; i<Classes; ++cp,++i ){
  466.         if( CompIn)
  467.             printf("%d, {%s} %d:\n",i ,cp->tags, cp->weight );
  468.         else
  469.             printf("%s, {%s} %d:\n", cp->name,cp->tags, cp->weight );
  470.         for( dp = cp->list; dp!=NULL; dp=dp->next ){
  471.             printf("(%d)%s\n",dp->cumul, dp->string );
  472.         }
  473.     }
  474. }
  475. #endif DUMP
  476.  
  477. char *my_alloc(n)
  478. unsigned n;
  479. {
  480.     register char *p;
  481.     p = malloc( n );
  482.     if( p==NULL ){
  483.         fprintf(stderr, "Out Of Memory\n");
  484.         exit(1);
  485.     }
  486.     return p;
  487. }
  488.  
  489. /*
  490.  * write the file to the standard output in compressed form, prepending
  491.  * the MAGIC byte for identification.
  492.  */
  493. compress(){
  494.     register class *cp;
  495.     register int i;
  496.  
  497.     putchar( MAGIC );
  498.     putw( Classes, stdout );    /* write the number of classes */
  499.     putw( -Classes, stdout );    /* write this to make sure */
  500.  
  501.     if( !CompIn ){
  502.         cp = lookup("MAIN/ ");        /* get main */
  503.         if( cp == NULL ){
  504.             fprintf(stderr, "MAIN undefined\n");
  505.             exit(1);
  506.         }
  507.         CompMain = cp - Class;
  508.     }
  509.     putw( CompMain, stdout );
  510.     cp = Class;
  511.     i  = Classes;
  512.     while(i--) comp1(cp++);
  513. }
  514. /*
  515.  * write a 'class' record in compressed format
  516.  */
  517. comp1(cp)
  518. register class *cp;
  519. {
  520.     register char *p;
  521.     register defn *dp;
  522.     register int n;
  523.  
  524.     putw( cp->weight, stdout );    /* write total weight */
  525.     p = cp->tags;
  526.     if( strcmp(p,NullTags) != 0 )    /* special case " " -> "" */
  527.         fputs( p, stdout );        /* write tags */
  528.     putchar(0);            /* delimiter */
  529.     n = 0;
  530.     dp = cp->list;
  531.     while( dp!= NULL ){
  532.         ++n;        /* count the defs */
  533.         dp = dp->next;
  534.     }
  535.     putw( n, stdout );    /* write the count of them */
  536.     dp = cp->list;
  537.     while( dp != NULL ){
  538.         compdef(dp);
  539.         dp = dp->next;    /* compress them */
  540.     }
  541. }
  542. compdef(dp)
  543. register defn *dp;
  544. {
  545.     register char *p;
  546.     register int c;
  547.     putw( dp-> cumul , stdout );    /* write its cumul weight */
  548.     p = dp->string;
  549.     while( (c = *p++) != '\0' ){
  550.         if( c==BSLASH){
  551.             if(!CompIn && isalnum(*p) ){    /* a ref */
  552.                 class *cp;
  553.                 cp = lookup(p);        /* find it */
  554.                 if( cp == NULL ){
  555.                     fprintf( stderr, "Undefined class: ");
  556.                     while( *p != SLASH ) fputc( *p++, stderr);
  557.                     fputc('\n', stderr );
  558.                     exit(1);
  559.                 }else{
  560.                     printf("%c%d", BSLASH, cp-Class );
  561.                     while( *p != SLASH ) ++p;
  562.                 }
  563.             }else{        /* is escape seq */
  564.                 putchar( BSLASH );
  565.                 putchar( *p++ );
  566.             }
  567.         }else{
  568.             putchar(c);
  569.         }
  570.     }
  571.     putchar(0);
  572. }
  573.  
  574. /*
  575.  * readcomp reads the compressed format of the file into core.
  576.  * the MAGIC char has been read already.
  577.  */
  578. readcomp(){
  579.     register class *cp;
  580.     register int i;
  581.     Classes = getw( InFile );
  582.     if( Classes <= 0 || getw( InFile ) + Classes != 0 )
  583.         badfile();    /* format check */
  584.     CompMain = getw( InFile );        /* read that next */
  585.     Class = (class*) my_alloc( (unsigned)(Classes*sizeof(class)) );
  586.     for( i= Classes, cp = Class; i--; ++cp)readcclass(cp);
  587. }
  588.  
  589. readcclass(cp)
  590. register class *cp;
  591. {
  592.     register int n;
  593.     register defn *dp;
  594.     defn **dput;
  595.  
  596.     char store[MAXDEF];    /* for tags */
  597.     cp->weight = getw( InFile );
  598.     instring(store,MAXDEF);
  599.     cp->tags = ( store[0] == '\0' )? NullTags: save( store );
  600.     n = getw( InFile );
  601.     if( n<=0 ) badfile();
  602.     dput = &(cp->list);    /* link on here */
  603.     while(n--){
  604.         dp = (defn *)my_alloc( (unsigned) sizeof( defn));
  605.         *dput = dp;
  606.         dp->cumul = getw( InFile );
  607.         instring(store, MAXDEF );
  608.         dp->string = save( store );
  609.         dput = &(dp->next);
  610.     }
  611.     *dput = NULL;        /* last one */
  612. }
  613.  
  614. instring( where, how_many )
  615. register char *where;
  616. register int how_many;
  617. {
  618.     register int c;
  619.     do{
  620.         c = getc( InFile );
  621.         if( c == EOF ) badfile();
  622.         *where++ = c;
  623.         if( c== '\0' ) return;
  624.     }while(--how_many);
  625.     badfile();
  626. }
  627. badfile(){
  628.     fprintf(stderr,"Bad file format\n");
  629.     exit(1);
  630. }
  631.  
  632. #ifndef unix
  633.  
  634. putw (word, stream)
  635. int word;
  636. FILE *stream;
  637. {
  638.     fwrite ((char *) &word, sizeof(int), 1, stream);
  639.     return (0);    /* we don't use it */
  640. }
  641.  
  642. getw (stream)
  643. FILE *stream;
  644. {
  645.     int word;
  646.  
  647.     fread ((char *) &word, sizeof(int), 1, stream);
  648.     return (word);
  649. }
  650.  
  651. #endif
  652.  
  653.